#include "sgp30_eswin.h"

// 命令定义
const uint8_t sgp30_init_air_quality[2]        = {0x20, 0x03};
const uint8_t sgp30_measure_air_quality[2]     = {0x20, 0x08};
const uint8_t sgp30_get_baseline[2]            = {0x20, 0x15};
const uint8_t sgp30_set_baseline[2]            = {0x20, 0x1E};
const uint8_t sgp30_set_humidity[2]            = {0x20, 0x61};
const uint8_t sgp30_measure_test[2]            = {0x20, 0x32};
const uint8_t sgp30_get_feature_set_version[2] = {0x20, 0x2F};
const uint8_t sgp30_get_serial_id[2]           = {0x36, 0x82};
const uint8_t sgp30_measure_raw_signals[2]     = {0x20, 0x50};

// 超时时间 (毫秒)
#define SGP30_TIMEOUT_MS (0x2000U)

uint8_t SGP30_CRC8(uint16_t data)
{
    uint8_t crc = 0xFF;

    // 处理高字节
    crc ^= (data >> 8);
    for (uint8_t i = 0; i < 8; i++) {
        if (crc & 0x80)
            crc = (crc << 1) ^ 0x31;
        else
            crc <<= 1;
    }

    // 处理低字节
    crc ^= (uint8_t)data;
    for (uint8_t i = 0; i < 8; i++) {
        if (crc & 0x80)
            crc = (crc << 1) ^ 0x31;
        else
            crc <<= 1;
    }

    return crc;
}

SGP30_Status SGP30_Init(SGP30_HandleTypeDef *hsgp, uint8_t i2cInstance, i2c_master_state_t *i2cState)
{
    if (hsgp == NULL) {
        return SGP30_ERR_INIT_FAILED;
    }

    // 初始化结构体
    memset(hsgp, 0, sizeof(SGP30_HandleTypeDef));

    hsgp->CO2               = 0;
    hsgp->TVOC              = 0;
    hsgp->baselineCO2       = 0;
    hsgp->baselineTVOC      = 0;
    hsgp->featureSetVersion = 0;
    hsgp->H2                = 0;
    hsgp->ethanol           = 0;
    hsgp->serialID          = 0;

    hsgp->i2cInstance = i2cInstance;
    hsgp->i2cState    = i2cState;

    // 获取序列号以验证连接
    return SGP30_GetSerialID(hsgp);
}

SGP30_Status SGP30_InitAirQuality(SGP30_HandleTypeDef *hsgp)
{
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_init_air_quality,
        sizeof(sgp30_init_air_quality),
        true, // 发送停止条件
        SGP30_TIMEOUT_MS);

    return (status == STATUS_SUCCESS) ? SGP30_SUCCESS : SGP30_ERR_I2C_TIMEOUT;
}

SGP30_Status SGP30_MeasureAirQuality(SGP30_HandleTypeDef *hsgp)
{
    uint8_t rx_data[6];

    // 发送测量命令
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_measure_air_quality,
        sizeof(sgp30_measure_air_quality),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    OS_DelayMs(12); // 等待测量完成

    // 读取数据
    status = I2C_DRV_MasterReceiveDataBlocking(
        hsgp->i2cInstance,
        rx_data,
        sizeof(rx_data),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    // 解析 CO2 数据
    uint16_t co2 = (rx_data[0] << 8) | rx_data[1];
    if (SGP30_CRC8(co2) != rx_data[2]) {
        return SGP30_ERR_BAD_CRC;
    }

    // 解析 TVOC 数据
    uint16_t tvoc = (rx_data[3] << 8) | rx_data[4];
    if (SGP30_CRC8(tvoc) != rx_data[5]) {
        return SGP30_ERR_BAD_CRC;
    }

    hsgp->CO2  = co2;
    hsgp->TVOC = tvoc;
    return SGP30_SUCCESS;
}

SGP30_Status SGP30_GetBaseline(SGP30_HandleTypeDef *hsgp)
{
    uint8_t rx_data[6];

    // 发送获取基线命令
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_get_baseline,
        sizeof(sgp30_get_baseline),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    OS_DelayMs(10); // 等待准备完成

    // 读取数据
    status = I2C_DRV_MasterReceiveDataBlocking(
        hsgp->i2cInstance,
        rx_data,
        sizeof(rx_data),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    // 解析基线数据
    uint16_t baseCO2 = (rx_data[0] << 8) | rx_data[1];
    if (SGP30_CRC8(baseCO2) != rx_data[2]) {
        return SGP30_ERR_BAD_CRC;
    }

    uint16_t baseTVOC = (rx_data[3] << 8) | rx_data[4];
    if (SGP30_CRC8(baseTVOC) != rx_data[5]) {
        return SGP30_ERR_BAD_CRC;
    }

    hsgp->baselineCO2  = baseCO2;
    hsgp->baselineTVOC = baseTVOC;
    return SGP30_SUCCESS;
}

SGP30_Status SGP30_SetBaseline(SGP30_HandleTypeDef *hsgp, uint16_t baselineCO2, uint16_t baselineTVOC)
{
    uint8_t tx_data[8];

    // 构建数据包: [命令] [TVOC_H, TVOC_L, CRC] [CO2_H, CO2_L, CRC]
    tx_data[0] = sgp30_set_baseline[0];
    tx_data[1] = sgp30_set_baseline[1];
    tx_data[2] = (uint8_t)(baselineTVOC >> 8);
    tx_data[3] = (uint8_t)baselineTVOC;
    tx_data[4] = SGP30_CRC8(baselineTVOC);
    tx_data[5] = (uint8_t)(baselineCO2 >> 8);
    tx_data[6] = (uint8_t)baselineCO2;
    tx_data[7] = SGP30_CRC8(baselineCO2);

    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        tx_data,
        sizeof(tx_data),
        true,
        SGP30_TIMEOUT_MS);

    return (status == STATUS_SUCCESS) ? SGP30_SUCCESS : SGP30_ERR_I2C_TIMEOUT;
}

SGP30_Status SGP30_SetHumidity(SGP30_HandleTypeDef *hsgp, uint16_t humidity)
{
    uint8_t tx_data[5];

    // 构建数据包: [命令] [HUM_H, HUM_L, CRC]
    tx_data[0] = sgp30_set_humidity[0];
    tx_data[1] = sgp30_set_humidity[1];
    tx_data[2] = (uint8_t)(humidity >> 8);
    tx_data[3] = (uint8_t)humidity;
    tx_data[4] = SGP30_CRC8(humidity);

    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        tx_data,
        sizeof(tx_data),
        true,
        SGP30_TIMEOUT_MS);

    return (status == STATUS_SUCCESS) ? SGP30_SUCCESS : SGP30_ERR_I2C_TIMEOUT;
}

SGP30_Status SGP30_GetFeatureSetVersion(SGP30_HandleTypeDef *hsgp)
{
    uint8_t rx_data[3];

    // 发送命令
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_get_feature_set_version,
        sizeof(sgp30_get_feature_set_version),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    OS_DelayMs(2); // 等待准备完成

    // 读取数据
    status = I2C_DRV_MasterReceiveDataBlocking(
        hsgp->i2cInstance,
        rx_data,
        sizeof(rx_data),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    // 解析版本数据
    uint16_t version = (rx_data[0] << 8) | rx_data[1];
    if (SGP30_CRC8(version) != rx_data[2]) {
        return SGP30_ERR_BAD_CRC;
    }

    hsgp->featureSetVersion = version;
    return SGP30_SUCCESS;
}

SGP30_Status SGP30_MeasureRawSignals(SGP30_HandleTypeDef *hsgp)
{
    uint8_t rx_data[6];

    // 发送命令
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_measure_raw_signals,
        sizeof(sgp30_measure_raw_signals),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    OS_DelayMs(25); // 等待测量完成

    // 读取数据
    status = I2C_DRV_MasterReceiveDataBlocking(
        hsgp->i2cInstance,
        rx_data,
        sizeof(rx_data),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    // 解析 H2 数据
    uint16_t h2 = (rx_data[0] << 8) | rx_data[1];
    if (SGP30_CRC8(h2) != rx_data[2]) {
        return SGP30_ERR_BAD_CRC;
    }

    // 解析乙醇数据
    uint16_t ethanol = (rx_data[3] << 8) | rx_data[4];
    if (SGP30_CRC8(ethanol) != rx_data[5]) {
        return SGP30_ERR_BAD_CRC;
    }

    hsgp->H2      = h2;
    hsgp->ethanol = ethanol;
    return SGP30_SUCCESS;
}

SGP30_Status SGP30_GeneralCallReset(uint8_t i2cInstance)
{
    uint8_t reset_cmd = 0x06;

    status_t status = I2C_DRV_MasterSendDataBlocking(
        i2cInstance,
        &reset_cmd,
        1,
        true,
        SGP30_TIMEOUT_MS);

    return (status == STATUS_SUCCESS) ? SGP30_SUCCESS : SGP30_ERR_I2C_TIMEOUT;
}

SGP30_Status SGP30_GetSerialID(SGP30_HandleTypeDef *hsgp)
{
    uint8_t rx_data[9];

    // 发送命令
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_get_serial_id,
        sizeof(sgp30_get_serial_id),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    OS_DelayMs(2); // 短延迟

    // 读取数据
    status = I2C_DRV_MasterReceiveDataBlocking(
        hsgp->i2cInstance,
        rx_data,
        sizeof(rx_data),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    // 解析序列号 (分三部分)
    uint16_t id1 = (rx_data[0] << 8) | rx_data[1];
    if (SGP30_CRC8(id1) != rx_data[2])
    return SGP30_ERR_BAD_CRC;

    uint16_t id2 = (rx_data[3] << 8) | rx_data[4];
    if (SGP30_CRC8(id2) != rx_data[5])
    return SGP30_ERR_BAD_CRC;

    uint16_t id3 = (rx_data[6] << 8) | rx_data[7];
    if (SGP30_CRC8(id3) != rx_data[8])
    return SGP30_ERR_BAD_CRC;

    // 组合64位序列号
    hsgp->serialID = ((uint64_t)id1 << 32) | ((uint64_t)id2 << 16) | id3;
    return SGP30_SUCCESS;
}

SGP30_Status SGP30_MeasureTest(SGP30_HandleTypeDef *hsgp)
{
    uint8_t rx_data[3];

    // 发送命令
    status_t status = I2C_DRV_MasterSendDataBlocking(
        hsgp->i2cInstance,
        (uint8_t *)sgp30_measure_test,
        sizeof(sgp30_measure_test),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    OS_DelayMs(220); // 等待自检完成

    // 读取数据
    status = I2C_DRV_MasterReceiveDataBlocking(
        hsgp->i2cInstance,
        rx_data,
        sizeof(rx_data),
        true,
        SGP30_TIMEOUT_MS);

    if (status != STATUS_SUCCESS) {
        return SGP30_ERR_I2C_TIMEOUT;
    }

    // 解析结果
    uint16_t result = (rx_data[0] << 8) | rx_data[1];
    if (SGP30_CRC8(result) != rx_data[2]) {
        return SGP30_ERR_BAD_CRC;
    }

    // 验证自检结果 (应为 0xD400)
    if (result != 0xD400) {
        return SGP30_SELF_TEST_FAIL;
    }

    return SGP30_SUCCESS;
}